#define QT_NO_DEBUG_OUTPUT
#include "gamemanager.h"
#include "utils.h"
#include "mapmanager.h"
#include <QElapsedTimer>
#include <QRandomGenerator>
#include <QTimer>
#include <QDebug>
GameManager::GameManager()
{
    init();
}

GameManager &GameManager::instance()
{
    static GameManager manager;
    return manager;
}

void GameManager::init()
{
    _players.clear();
    QSize size = MapManager::instance().background().size();
    QPointF player1_pos(size.width() * 0.05, size.height() / 2);
    QPointF player2_pos(size.width() * 0.95, size.height() / 2);
    Player player1(player1_pos, 1, 100, 600, 200, 1000);
    Player player2(player2_pos, 2, 100, 600, 200, 1000);
    _players.push_back(player1);
    _players.push_back(player2);

    initSimulator();
    initTimer_createrUnits();
    initTimer_updateSimulator();

    _simulator->addAgent(RVO::Vector2(player1_pos.x(), player1_pos.y()), 100, 10, 1, 1, 50, 0);
    _simulator->addAgent(RVO::Vector2(player2_pos.x(), player2_pos.y()), 100, 10, 1, 1, 50, 0);
}

void GameManager::initTimer_createrUnits()
{
    _timer_createrUnits = new QTimer(this);
    _timer_createrUnits->setTimerType(Qt::PreciseTimer); // 毫秒级, 不过还是会受时间片影响

    connect(_timer_createrUnits, &QTimer::timeout, this, [=](){
        if(_units_team1.size() + _units_team2.size() > 800){
             _timer_createrUnits->stop();
             QTimer::singleShot(25000, this, [=]{
                 rebuildSimulator();
                 _timer_createrUnits->start();
             });
        }
        for(int i = 0; i < _players.size(); ++i){
            float angle;
            if(_players[i].team == 1) { // 右侧扇区生成
                angle = (rand() % 180 - 90) * Utils::PI() / 180;
            } else { // 左侧扇区生成
                angle = (rand() % 180 + 90) * Utils::PI() / 180;
            }
//            if(_players[i].team == 1) { // 右侧扇区生成
//                angle = (rand() % 90 - 45) * Utils::PI() / 180;
//            } else { // 左侧扇区生成
//                angle = (rand() % 90 + 135) * Utils::PI() / 180;
//            }
            float distance = rand() % 100 + 100;

            RVO::Vector2 src(_players[i].pos.x() + distance * cos(angle), _players[i].pos.y() + distance * sin(angle));
            Unit unit;
            unit.radius = 15;
            unit.speed = 175;
            unit.pos = src;
            unit.ap = 5;
            unit.hp = 30;
            unit.attackrange = 60; // 两个身位, 大概?
            unit.team = _players[i].team;
            unit.id = _simulator->addAgent(src, 4 * unit.radius, 10U, 1.5F, 1.5F, 4 + unit.radius, unit.speed);
            if(_players[i].team == 1) _units_team1.append(unit);
            else if(_players[i].team == 2) _units_team2.append(unit);
            else qDebug() << "非法团队";
//            qDebug() << "创建节点于 : " << src.x() << ", " << src.y() << "team : " << unit.team;
        }
    });
}

void GameManager::initTimer_updateSimulator()
{
    _timer_updateSimulator = new QTimer(this);
    _timer_updateSimulator->setTimerType(Qt::PreciseTimer);
    connect(_timer_updateSimulator, &QTimer::timeout, this, &GameManager::updateSimulator);
}


void GameManager::initSimulator()
{
    _simulator = new RVO::RVOSimulator();
    _simulator->setAgentDefaults(25.0F, 10U, 1.5F, 1.5F, 10.0F, 200);
    std::vector<RVO::Vector2> obstacle1;
    std::vector<RVO::Vector2> obstacle2;
    std::vector<RVO::Vector2> obstacle3;
    std::vector<RVO::Vector2> obstacle4;

    // 设置边界:
    float width = MapManager::instance().background().width();
    float height = MapManager::instance().background().height();
    float border = 10.f;
    obstacle1.push_back(RVO::Vector2(0.f, 0.f));
    obstacle1.push_back(RVO::Vector2(width, 0.f));
    obstacle1.push_back(RVO::Vector2(width, -border));
    obstacle1.push_back(RVO::Vector2(0.f, -border));

    obstacle2.push_back(RVO::Vector2(0.f, height));
    obstacle2.push_back(RVO::Vector2(width, height));
    obstacle2.push_back(RVO::Vector2(width, height + border));
    obstacle2.push_back(RVO::Vector2(0.f, height + border));

    obstacle3.push_back(RVO::Vector2(width, -border));
    obstacle3.push_back(RVO::Vector2(width + border, -border));
    obstacle3.push_back(RVO::Vector2(width + border, height + border));
    obstacle3.push_back(RVO::Vector2(width, height + border));

    obstacle4.push_back(RVO::Vector2(-border, -border));
    obstacle4.push_back(RVO::Vector2(0.f, -border));
    obstacle4.push_back(RVO::Vector2(0.f, height + border));
    obstacle4.push_back(RVO::Vector2(-border, height + border));

    _simulator->addObstacle(obstacle1);
    _simulator->addObstacle(obstacle2);
    _simulator->addObstacle(obstacle3);
    _simulator->addObstacle(obstacle4);

    _simulator->processObstacles();
}


void GameManager::paintUnits(QPainter & painter) const
{
    painter.setPen(Qt::blue);
    painter.setBrush(Qt::blue);
    painter.drawEllipse(_players[0].pos, 50, 50);
    painter.setPen(Qt::red);
    painter.setBrush(Qt::red);
    painter.drawEllipse(_players[1].pos, 50, 50);

    painter.setPen(Qt::blue);
    painter.setBrush(Qt::blue);
    for(auto& unit : _units_team1){
        painter.drawEllipse(QPointF(unit.pos.x(), unit.pos.y()), unit.radius, unit.radius);
    }

    painter.setPen(Qt::red);
    painter.setBrush(Qt::red);
    for(auto& unit : _units_team2){
        painter.drawEllipse(QPointF(unit.pos.x(), unit.pos.y()), unit.radius, unit.radius);
    }
}

void GameManager::start()
{
    bool started = false;
    if(started) return;
    started = true;
    _timer_updateSimulator->start(2);
    _timer_createrUnits->start(16);
    eTimer.start();
}

void GameManager::updateSimulator()
{
    static QElapsedTimer eTimer;
    static bool first = true;

    if (first) {
        eTimer.start();
        first = false;
        return; // 第一帧跳过
    }

    // 使用真实经过的时间作为时间步长
    qint64 dt_ms_real = eTimer.restart();
    double dt_s_real = dt_ms_real * 0.001;
    double timeStep = std::min(dt_s_real, 1.0 / 15.0); // 最低15fps
    _simulator->setTimeStep(timeStep);

    RVO::Vector2 dst_team1(_players[1].pos.x(), _players[1].pos.y());
    for(int i = 0; i < _units_team1.size(); ++i){
        size_t id = _units_team1[i].id;
        _units_team1[i].pos = _simulator->getAgentPosition(id);

        RVO::Vector2 goalVector(dst_team1 - _units_team1[i].pos);
        if (RVO::absSq(goalVector) > 1.0f) {
            goalVector = RVO::normalize(goalVector);
        }

        _simulator->setAgentPrefVelocity(id, goalVector * _units_team1[i].speed);
    }

    RVO::Vector2 dst_team2(_players[0].pos.x(), _players[0].pos.y());
    for(int i = 0; i < _units_team2.size(); ++i){
        size_t id = _units_team2[i].id;
        _units_team2[i].pos = _simulator->getAgentPosition(id);

        RVO::Vector2 goalVector(dst_team2 - _units_team2[i].pos);
        if (RVO::absSq(goalVector) > 1.0f) {
            goalVector = RVO::normalize(goalVector);
        }
        _simulator->setAgentPrefVelocity(id, goalVector * _units_team2[i].speed);
    }
    _simulator->doStep();
//    checkCollisions(); // 碰撞检测
}

void GameManager::checkCollisions()
{
    // TODO: 用四叉树优化,目前这个太low了
    qint64 currentTime = eTimer.elapsed(); // 当前时间
    if(rand() % 2 == 0){
        for(auto it1 = _units_team1.begin(); it1 != _units_team1.end(); ++it1){
            // 判断当前的组1单位能不能攻击
            bool canit1attack = currentTime - it1->lastattack > it1->attackfrequency;
            for(auto it2 = _units_team2.begin(); it2 != _units_team2.end(); ++it2){
                RVO::Vector2 direction = it1->pos - it2->pos;
                float distance = sqrt(direction.x()*direction.x() + direction.y() * direction.y());
                if(distance <= it2->attackrange){
                    // 判断当前的组2单位能不能攻击
                    if(currentTime - it2->lastattack < it2->attackfrequency) continue;
                    _simulator->setAgentPrefVelocity(it2->id, {0, 0});
                    it1->hp -= it2->ap;
                    it2->lastattack = currentTime;
                }
                if(distance <= it1->attackrange && canit1attack){
                    _simulator->setAgentPrefVelocity(it1->id, {0, 0});
                    it2->hp -= it1->ap;
                    it1->lastattack = currentTime;
                }
            }
        }
    } else {
        for(auto it2 = _units_team2.begin(); it2 != _units_team2.end(); ++it2){
            // 判断当前的组2单位能不能攻击
            bool canit2attack = currentTime - it2->lastattack > it2->attackfrequency;
            for(auto it1 = _units_team1.begin(); it1 != _units_team1.end(); ++it1){
                RVO::Vector2 direction = it2->pos - it1->pos;
                float distance = sqrt(direction.x()*direction.x() + direction.y() * direction.y());
                if(distance <= it1->attackrange){
                    // 判断当前的组2单位能不能攻击
                    if(currentTime - it1->lastattack < it1->attackfrequency) continue;
                    _simulator->setAgentPrefVelocity(it1->id, {0, 0});
                    it2->hp -= it1->ap;
                    it1->lastattack = currentTime;
                }
                if(distance <= it2->attackrange && canit2attack){
                    _simulator->setAgentPrefVelocity(it2->id, {0, 0});
                    it1->hp -= it2->ap;
                    it2->lastattack = currentTime;
                }
            }
        }
    }
    // 清理的同时,顺便处理玩家攻击
    bool p1canAttack = currentTime - _players[0].lastattack > _players[0].attackfrequency;
    bool p2canAttack = currentTime - _players[1].lastattack > _players[1].attackfrequency;
    QPointF pos1(_players[0].pos), pos2(_players[1].pos);
    for(auto it1 = _units_team1.begin(); it1 != _units_team1.end();){
        if(p2canAttack){
            RVO::Vector2 direction(it1->pos.x() - pos2.x(), it1->pos.y() - pos2.y());
            float distance = sqrt(direction.x()*direction.x() + direction.y() * direction.y());
            if(distance < _players[1].attackrange){
                it1->hp -= _players[1].ap;
                _players[1].lastattack = currentTime;
                p2canAttack = false;
            }
        }

        if(it1->hp < 0){
            // 这边不能挪到同一个位置,会卡,所以用rand把它们分开了
            _simulator->setAgentPosition(it1->id, RVO::Vector2(-666 - rand() % 10000, -666 - rand() % 10000));
            _simulator->setAgentPrefVelocity(it1->id, RVO::Vector2(0, 0));
            _simulator->setAgentMaxSpeed(it1->id, 0);
            it1 = _units_team1.erase(it1);
        } else ++it1;
    }
    for(auto it2 = _units_team2.begin(); it2 != _units_team2.end();){
        if(p1canAttack){
            RVO::Vector2 direction(it2->pos.x() - pos1.x(), it2->pos.y() - pos1.y());
            float distance = sqrt(direction.x()*direction.x() + direction.y() * direction.y());
            if(distance < _players[0].attackrange){
                it2->hp -= _players[0].ap;
                _players[0].lastattack = currentTime;
                p1canAttack = false;
            }
        }
        if(it2->hp < 0) {
            _simulator->setAgentPosition(it2->id, RVO::Vector2(-666 - rand() % 10000, -666 - rand() % 10000));
            _simulator->setAgentPrefVelocity(it2->id, RVO::Vector2(0, 0));
            _simulator->setAgentMaxSpeed(it2->id, 0);
            it2 = _units_team2.erase(it2);
        } else ++it2;
    }
}

void GameManager::rebuildSimulator()
{
    // 这个函数万万不能频繁调用, 会卡死的
    // 保存当前有效单位
    QList<Unit> validTeam1, validTeam2;
    for(const auto& unit : _units_team1) {
        if(unit.hp > 0) validTeam1.append(unit);
    }
    for(const auto& unit : _units_team2) {
        if(unit.hp > 0) validTeam2.append(unit);
    }

    // 更新模拟器
    delete _simulator;
    initSimulator();

    // 重新添加单位
    _units_team1.clear();
    for(auto& unit : validTeam1) {
        unit.id = _simulator->addAgent(unit.pos, 4 * unit.radius, 10U, 1.5F, 1.5F, 4 + unit.radius, unit.speed);
        _units_team1.append(unit);
    }
    _units_team2.clear();
    for(auto& unit : validTeam2) {
        unit.id = _simulator->addAgent(unit.pos, 4 * unit.radius, 10U, 1.5F, 1.5F, 4 + unit.radius, unit.speed);
        _units_team2.append(unit);
    }

    // 重新添加玩家
    _simulator->addAgent(RVO::Vector2(_players[0].pos.x(), _players[0].pos.y()), 100, 10, 1, 1, 50, 0);
    _simulator->addAgent(RVO::Vector2(_players[1].pos.x(), _players[1].pos.y()), 100, 10, 1, 1, 50, 0);
}
